﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
using System.Diagnostics;

namespace Ddbs.QE.Parser.Front.Serialization
{
    [Serializable]
    public enum DataType
    {
        INT = 1,
        VCAHR
    }

    [Serializable]
    public enum ConditionType
    {
        //relation
        AND = 1,
        OR,
        

        // Predict,
        LT,
        LE,
        EQ,
        NEQ,
        GT,
        GE,

        NOT,
        //value
        COLUMN,
        STRVAL,
        INTVAL
        
    }

    public class ConditionTypeMapper
    {
        public static Dictionary<ConditionType, string> ConditionType2String;
        static ConditionTypeMapper()
        {
            ConditionType2String = new Dictionary<ConditionType, string>();
            ConditionType2String[ConditionType.AND] = "and";
            ConditionType2String[ConditionType.OR] = "or";
            ConditionType2String[ConditionType.NOT] = "not";
            ConditionType2String[ConditionType.NEQ] = "!=";
            ConditionType2String[ConditionType.EQ] = "=";
            ConditionType2String[ConditionType.LE] = "<=";
            ConditionType2String[ConditionType.LT] = "<";
            ConditionType2String[ConditionType.GE] = ">=";
            ConditionType2String[ConditionType.GT] = ">";
            
        }        
    }


    [Serializable]
    public class Site
    {
        private int id;
        private string siteName;

        public string SiteName
        {
            get { return siteName; }
            set { siteName = value; }
        }

        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        private string ip;

        public string Ip
        {
            get { return ip; }
            set { ip = value; }
        }
        private int port;

        public int Port
        {
            get { return port; }
            set { port = value; }
        }

    }
    [Serializable]
    public class Column
    {
        private string columnName;
        [XmlIgnore]
        private string tableName;
        [XmlIgnore]
        public string TableName
        {
            get { return tableName; }
            set { tableName = value; }
        }
        public string ColumnName
        {
            get { return columnName; }
            set { columnName = value; }
        }
        private DataType dataType;

        public DataType DataType
        {
            get { return dataType; }
            set { dataType = value; }
        }
        private int length;

        public int Length
        {
            get { return length; }
            set { length = value; }
        }
        [XmlIgnore]
        private bool isAllColumn;
        [XmlIgnore]
        public bool IsAllColumn
        {
            get { return isAllColumn; }
            set { isAllColumn = value; }
        }
        [XmlIgnore]
        private bool hasTableName;
        [XmlIgnore]
        public bool HasTableName
        {
            get { return hasTableName; }
            set { hasTableName = value; }
        }

        public Column dup()
        {
            return this;
        }

        public  bool isSameTable(Column c)
        {
            return (tableName == c.tableName);
        }


    }
    [Serializable]
    public class Condition
    {
        public Condition()
        {
            children = new List<Condition>();
        }

        private ConditionType type;

        public ConditionType Type
        {
            get { return type; }
            set { type = value; }
        }
        private List<Condition> children;
         [XmlArrayItem(Type = typeof(Condition)),
         XmlArrayItem(Type = typeof(ColumnVal)),
         XmlArrayItem(Type = typeof(IntVal)),
        XmlArrayItem(Type = typeof(StrVal))]

        public List<Condition> Children
        {
            get { return children; }
            set { children = value; }
        }

         public override string ToString()
         {
             StringBuilder builder = new StringBuilder();
             if (type < ConditionType.NOT)
             {
                 int l = children.Count;
                 for(int i=0;i<l;++i)
                 {
                     if (i == 0) { builder.Append("( "); }
                     builder.Append(children.ElementAt(i).ToString());
                     if(i!=l-1)
                     {
                         builder.Append(ConditionTypeMapper.ConditionType2String[Type]);

                     }
                     if (i == l - 1)
                     { builder.Append(" )"); }
                 }
             }else {
                 builder.Append("( not ");
                 builder.Append(children.First().ToString());
                 builder.Append(" )");

             }
             return builder.ToString();
         }


         public  string toString()
         {
             StringBuilder builder = new StringBuilder();
             if (type < ConditionType.NOT)
             {
                 int l = children.Count;
                 for (int i = 0; i < l; ++i)
                 {
                     if (i == 0) { builder.Append("( "); }
                     builder.Append(children.ElementAt(i).toString());
                     if (i != l - 1)
                     {
                         builder.Append(ConditionTypeMapper.ConditionType2String[Type]);

                     }
                     if (i == l - 1)
                     { builder.Append(" )"); }
                 }
             }
             else if (type == ConditionType.NOT)
             {
                 builder.Append("( not ");
                 builder.Append(children.First().toString());
                 builder.Append(" )");

             }
             else if (type == ConditionType.COLUMN)
             {
                 //StringBuilder builder = new StringBuilder();
                 Column columnRef = (this as ColumnVal).ColumnRef;
                 if (columnRef.HasTableName)
                 {
                     builder.Append(columnRef.TableName);
                     builder.Append(".");
                 }
                 if (columnRef.IsAllColumn)
                 {
                     builder.Append("*");

                 }
                 else
                 {
                     builder.Append(columnRef.ColumnName);
                 }


             }
             else if (type == ConditionType.STRVAL)
             {
                 return (this as StrVal).Val;
             } if (type == ConditionType.INTVAL)
             {
                 return (this as IntVal).Val.ToString();
             }
             return builder.ToString();
         }
        //no not
         public static void normalize(Condition c)
         {
             switch (c.Type)
             {
                 case ConditionType.AND:
                     foreach (Condition child in c.Children)
                     {
                         normalize(child);
                     }
                     List<Condition> tmpAndChildren = new List<Condition>();
                     foreach (Condition child in c.Children)
                     {
                         if(child.Type== ConditionType.AND)
                         {
                            tmpAndChildren.AddRange(child.Children);
                            
                         }else {
                         
                            tmpAndChildren.Add(child);
                         }
                     }
                     if (tmpAndChildren.Count == 1)
                     {
                         c.Type = tmpAndChildren.First().Type;
                         c.Children = tmpAndChildren.First().Children;
                     
                     }
                     else
                     {
                         c.Children = tmpAndChildren;
                     }
                     break;
                 case ConditionType.OR:
                     foreach (Condition child in c.Children)
                     {
                         normalize(child);
                     }
                     List<Condition> tmpOrChildren = new List<Condition>();
                     int childrenCount = c.Children.Count;
                     int[] subLimits = new int[childrenCount];
                     int[] subIndex = new int[childrenCount];
                     int cur=0;
                     foreach (Condition child in c.Children)
                     {
                         if (child.Type == ConditionType.AND)
                         {
                             subLimits[cur] = child.Children.Count;
                         }
                         else {
                             subLimits[cur] = 1;
                         }
                         ++cur;
                     }
                     while (cur < childrenCount)
                     {
                        //generate an or
                         Condition cond = new Condition();
                         cond.Type = ConditionType.OR;
                         foreach (Condition child in c.Children)
                         {
                             if (isPred(child))
                             {
                                 cond.Children.Add(child);
                             }
                             else if (child.Type == ConditionType.OR)
                             {
                                 cond.Children.AddRange(child.Children);
                             }
                             else { 
                                //and, each subchild is an or a simplePred
                                 foreach (Condition subChild in child.Children)
                                 {
                                     if (subChild.Type == ConditionType.OR)
                                     {
                                         cond.Children.AddRange(subChild.Children);
                                     }
                                     else {
                                         cond.Children.Add(subChild);
                                     }
                                 }

                             }
                         }
                         if (cond.Children.Count == 1)
                         {
                             cond.Type = cond.Children.First().Type;
                             cond.Children = cond.Children.First().Children;
                         }
                         tmpOrChildren.Add(cond);


                         //get next
                         while (cur < childrenCount && (++(subIndex[cur])) >= subLimits[cur])
                         {
                             subIndex[cur] = 0;
                             ++cur;
                         }

                     }
                     if (tmpOrChildren.Count == 1)
                     {
                         c.Type = tmpOrChildren.First().Type;
                         c.Children = tmpOrChildren.First().Children;
                     }
                     else {
                         c.Children = tmpOrChildren;
                     }

                     break;
                 default:
                     /*if (isPred(c))
                     {
 
                     }*/
                     break;
                     
             }
         }

         delegate bool PredDelegate<T>(T l, T r) where T : System.IComparable<T>;

         private static void getInvolvedColumnsHelper(Condition c, HashSet<Column> columns)
         {
             if (c.Type == ConditionType.AND || c.Type == ConditionType.OR || isPred(c))
             {
                 foreach (Condition child in c.Children)
                 {
                     getInvolvedColumnsHelper(child, columns);
                 }
             }
             else if(c.Type == ConditionType.COLUMN){ 
                 columns.Add((c as ColumnVal).ColumnRef);
             }
         }

         public static HashSet<Column> getInvolvedColumns(Condition c)
         {
             HashSet<Column> columns = new HashSet<Column>();
             getInvolvedColumnsHelper(c, columns);
             return columns;
 
         }
         public static HashSet<Table> getInvolvedTables(HashSet<Column> columns)
         {
            HashSet<Table> tables = new HashSet<Table>(); 
            foreach(Column c in columns)
            {
                tables.Add(ConfHelper.name2table[c.TableName]);
            }
            return tables;
         }
         public static HashSet<Table> getInvolvedTables(Condition c)
         {

             return getInvolvedTables(getInvolvedColumns(c));
         }


        private static bool Eq<T>(T l, T r) where T : System.IComparable<T>
        {
            return l.CompareTo(r)==0;
        }
        private static bool Neq<T>(T l, T r) where T : System.IComparable<T>
        {
            return l.CompareTo(r) != 0;
        }
        private static bool Ge<T>(T l, T r) where T : System.IComparable<T>
        {
            return l.CompareTo(r) >= 0;
        }
        private static bool Gt<T>(T l, T r) where T : System.IComparable<T>
        {
            return l.CompareTo(r) > 0;
        }
        private static bool Le<T>(T l, T r) where T : System.IComparable<T>
        {
            return l.CompareTo(r) <= 0;
        }
        private static bool Lt<T>(T l, T r) where T : System.IComparable<T>
        {
            return l.CompareTo(r) < 0;
        }
        private static bool AlwaysTrue<T>(T l, T r) where T : System.IComparable<T>
        {
            return true;
        }
        private static bool AlwaysFalse<T>(T l, T r) where T : System.IComparable<T>
        {
            return false;
        }
        private static int tryEvaluateHelper(Condition cond , PredDelegate<int> intDelegate, PredDelegate<string> strDelegate)
         {

                     if (cond.Children.Count == 2)
                     {
                         if (cond.Children.First().Type == ConditionType.INTVAL &&
                            cond.Children.ElementAt(1).Type == ConditionType.INTVAL)
                         {

                             if(intDelegate((cond.Children.First() as IntVal).Val, (cond.Children.ElementAt(1) as IntVal).Val))
                             {
                                 return 1;
                             }
                             return -1;
                         }
                         else if (cond.Children.First().Type == ConditionType.STRVAL &&
                           cond.Children.ElementAt(1).Type == ConditionType.STRVAL)
                         {
                             if (strDelegate((cond.Children.First() as StrVal).Val , (cond.Children.ElementAt(1) as StrVal).Val))
                             {
                                 return 1;
                             }
                             return -1;
                         }
                     }
                     return 0;
         }

        //-1 false
        //1  true
        //0 can't determine

         public static int tryEvaluate(Condition cond)
         {
             int result = 0;
             List<Condition> trueChildren = new List<Condition>();
             switch (cond.Type)
             { 


                case ConditionType.AND:

                     foreach (Condition child in cond.Children)
                     {
                         int tmp = tryEvaluate(child);
                         if (tmp == -1)
                         {
                             return -1;
                         }
                         else if (tmp == 1)
                         {
                             trueChildren.Add(child);
                         }
                     }
                     if (trueChildren.Count < cond.Children.Count)
                     {
                         foreach (Condition child in trueChildren)
                         {
                             cond.Children.Remove(child);
                         }
                         if (cond.Children.Count ==1)
                         {
                             cond.Type = cond.Children.First().Type;
                             cond.Children = cond.Children.First().Children;
                         }
                     }
                     else {

                         return 1;
                     
                     }
                     result = 0;
                     break;
                 case ConditionType.OR:

                     List<Condition> falseChildren = new List<Condition>();

                     foreach (Condition child in cond.Children)
                     {
                         int tmp = tryEvaluate(child);
                         if (tmp == 1)
                         {
                             return 1;
                         }
                         else if (tmp == -1)
                         {
                             falseChildren.Add(child);
                         }
                     }
                     if (falseChildren.Count < cond.Children.Count)
                     {
                         foreach (Condition child in trueChildren)
                         {
                             cond.Children.Remove(child);
                         }
                         if (cond.Children.Count ==1)
                         {
                             cond.Type = cond.Children.First().Type;
                             cond.Children = cond.Children.First().Children;
                         }

                     }
                     else {

                         return -1;
                     
                     }
                     result = 0;
                     break;

                 case ConditionType.EQ:
                     PredDelegate<int> intEq =  new PredDelegate<int>(Eq);
                     PredDelegate<string> strEq = new PredDelegate<string>(Eq);
                     result = tryEvaluateHelper(cond, intEq, strEq );
                     break;
                 case ConditionType.NEQ:
                     PredDelegate<int> intNeq =  new PredDelegate<int>(Neq);
                     PredDelegate<string> strNeq = new PredDelegate<string>(Neq);
                     result = tryEvaluateHelper(cond, intNeq, strNeq);
                     break;
                 case ConditionType.GE:
                     PredDelegate<int> intGe = new PredDelegate<int>(Ge);
                     PredDelegate<string> strGe = new PredDelegate<string>(Ge);
                     result = tryEvaluateHelper(cond, intGe, strGe);
                     break;
                 case ConditionType.GT:
                     PredDelegate<int> intGt = new PredDelegate<int>(Gt);
                     PredDelegate<string> strGt = new PredDelegate<string>(Gt);
                     result = tryEvaluateHelper(cond, intGt, strGt);
                     break;
                 case ConditionType.LE:
                     PredDelegate<int> intLe = new PredDelegate<int>(Le);
                     PredDelegate<string> strLe = new PredDelegate<string>(Le);
                     result = tryEvaluateHelper(cond, intLe, strLe);
                     break;
                 case ConditionType.LT:
                     PredDelegate<int> intLt = new PredDelegate<int>(Lt);
                     PredDelegate<string> strLt = new PredDelegate<string>(Lt);
                     result = tryEvaluateHelper(cond, intLt, strLt);
                     break;
                 

                 default:
                     result = 0;
                     break;
             
             }
             return result;
         }

         public static bool isConfilct(Condition l, Condition r)
         {

             if (r.Type == ConditionType.AND || r.Type == ConditionType.OR)
             {
                         return isConfilct(r, l);
             }
             bool result = true;
             switch (l.Type)
             {
                 case ConditionType.AND:

                     foreach (Condition child in l.Children)
                     {
                         if (isConfilct(child, r))
                         {
                             return true;
                         }
                     }
                     result = false;
                     break;
                 case ConditionType.OR:

                     foreach (Condition child in l.Children)
                     {
                         if (!isConfilct(child, r))
                         {
                             return false;
                         }
                     }
                     result = true;
                     break;

                 case ConditionType.EQ:

                     switch (r.Type)
                     {
                        
                     }
                     break;
                 case ConditionType.NEQ:
                     break;
                 case ConditionType.GE:
                     break;
                 case ConditionType.GT:
                     break;
                 case ConditionType.LE:
                     break;
                 case ConditionType.LT:
                     break;
                 

                 default:
                     break;
             }
             return result;

         }

         public static bool isPred(Condition cond)
         {
             return (cond.Type > ConditionType.OR )&&( cond.Type < ConditionType.NOT);
         }

         public static bool isColumnPred(Condition cond)
         {
             if(!isPred(cond))
             {
                 return false;
             }
             if (cond.Children.First().Type == ConditionType.COLUMN)
             {
                 return (cond.Children.ElementAt(1).Type != ConditionType.COLUMN );
             }else{
                 return (cond.Children.ElementAt(1).Type == ConditionType.COLUMN);
             }
            
         }
         
         public static bool isJoinCond(Condition cond)
         {
             if (!isPred(cond))
             {
                 return false;
             }
             if ((cond.Children == null) || (cond.Children.Count != 2) )
             {
                 return false;
             }
             if ((cond.Children.First().Type != ConditionType.COLUMN)
                 || (cond.Children.ElementAt(1).Type != ConditionType.COLUMN))
             {
                 return false;
             }
             return true;
         }
         public static bool isSimpleOr(Condition cond)
         {
             
             Serialization.Column column = null;

             return isSimpleHelper(ref column, cond);
         }
         private static bool isSimpleHelper(ref Serialization.Column column, Condition cond)
        {
            if (!(cond.Type == ConditionType.OR  || cond.Type == ConditionType.AND))
            {
                return false;
            }
            foreach (Condition child in cond.Children)
            {
                if (child.Type == ConditionType.COLUMN)
                {
                    if (column == null)
                    {
                        column = (child as ColumnVal).ColumnRef;
                    }
                    else
                    {

                        if (!column.isSameTable( (child as ColumnVal).ColumnRef))
                        {
                            return false;
                        }
                    }
                }
                else if (cond.Type == ConditionType.OR || cond.Type == ConditionType.AND)
                {
                    if (!isSimpleHelper(ref column, child))
                    {
                        return false;
                    }
                }
                else {
                    return false;
                }
            }
            return true;

        }
         
    }
    [XmlInclude(typeof(ColumnVal))]
    [Serializable]
    public class ColumnVal : Condition
    {
        private Column columnRef;

        public Column ColumnRef
        {
            get { return columnRef; }
            set { columnRef = value; }
        }
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            if (columnRef.HasTableName)
            {
                builder.Append(columnRef.TableName);
                builder.Append("_");
            }
            if (columnRef.IsAllColumn)
            {
                builder.Append("*");

            }
            else {
                builder.Append(columnRef.ColumnName);
            }
            return builder.ToString();
        }

        

    }
    [XmlInclude(typeof(IntVal))]
    [Serializable]
    public class IntVal : Condition
    {
        private int val;

        public int Val
        {
            get { return val; }
            set { val = value; }
        }
        public override string ToString()
        {
            return val.ToString();
        }
        
    }
    [XmlInclude(typeof(StrVal))]
    [Serializable]
    public class StrVal : Condition
    {
        private string val;

        public string Val
        {
            get { return val; }
            set { val = value; }
        }
        public override string ToString()
        {
            return val;
        }
       
    }

    [Serializable]
    public class Fragment
    {
        private int rowCount;
        private int rowSize;

        public int RowSize
        {
            get { return rowSize; }
            set { rowSize = value; }
        }
        
        public int RowCount
        {
            get { return rowCount; }
            set { rowCount = value; }
        }
        private int id;
        private string tableName;

        public string TableName
        {
            get { return tableName; }
            set { tableName = value; }
        }
        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        private List<Site> sites;

        public List<Site> Sites
        {
            get { return sites; }
            set { sites = value; }
        }

        


    }
    [Serializable]
    public class HFragment : Fragment
    {
        private Condition cond;
        

        public Condition Cond
        {
            get { return cond; }
            set { cond = value; }
        }
    }
    [Serializable]
    public class VFragment : Fragment
    {
        private List<Column> columnRefs;
        private Column joinColumn;

        public Column JoinColumn
        {
            get { return joinColumn; }
            set { joinColumn = value; }
        }
        public List<Column> ColumnRefs
        {
            get { return columnRefs; }
            set { columnRefs = value; }
        }

        
    }

    [Serializable]
    public class Table
    {
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private List<Column> columns;

        public List<Column> Columns
        {
            get { return columns; }
            set { columns = value; }
        }
        private Column primaryKey;

        public Column PrimaryKey
        {
            get { return primaryKey; }
            set { primaryKey = value; }
        }

        private List<Fragment> fragments;
         [XmlArrayItem(Type = typeof(Fragment)),
        XmlArrayItem(Type = typeof(HFragment)),
        XmlArrayItem(Type = typeof(VFragment))]
        public List<Fragment> Fragments
        {
            get { return fragments; }
            set { fragments = value; }
        }


    }
    [Serializable]
    public class Database
    {
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private List<Table> tables;

        public List<Table> Tables
        {
            get { return tables; }
            set { tables = value; }
        }

    }
    public class ConfHelper
    {
        public static Dictionary<string, HashSet<string>> col2tbls;
        public static Dictionary<string, HashSet<string>> tbl2cols;
        public static Dictionary<string, Ddbs.QE.Parser.Front.Serialization.Table> name2table;
        public static Dictionary<string, Ddbs.QE.Parser.Front.Serialization.Column> name2column;
        public ConfHelper(Conf conf)
        {
            col2tbls = new Dictionary<string, HashSet<string>>();
            tbl2cols = new Dictionary<string, HashSet<string>>();
            name2table = new Dictionary<string, Serialization.Table>();
            name2column = new Dictionary<string, Serialization.Column>();

            List<Ddbs.QE.Parser.Front.Serialization.Table> tables = conf.Database.Tables;
            foreach (Ddbs.QE.Parser.Front.Serialization.Table t in tables)
            {
                tbl2cols[t.Name] = new HashSet<string>();
                name2table[t.Name] = t;
                foreach (Ddbs.QE.Parser.Front.Serialization.Column c in t.Columns)
                {
                    if (!col2tbls.ContainsKey(c.ColumnName))
                    {
                        col2tbls[c.ColumnName] = new HashSet<string>();
                    }
                    name2column[t.Name + "." + c.ColumnName] = c;
                    col2tbls[c.ColumnName].Add(t.Name);
                    tbl2cols[t.Name].Add(c.ColumnName);
                }
            }
        }
    }

    [Serializable]
    public class Conf
    {
        private List<Site> sites;

        public List<Site> Sites
        {
            get { return sites; }
            set { sites = value; }
        }
        private Database database;

        public Database Database
        {
            get { return database; }
            set { database = value; }
        }
        public static void test()
        {
            SerializeTest();
          //  Console.WriteLine("Pass Conf  serialize test !");
            DeserializeTest();
          //  Console.WriteLine("Pass Conf  deserialize test !");
        }

        public static Conf DeSerializeConf(string filename)
        {
            Conf tmp = null;
            TextReader reader = null;
            System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Conf));
            try
            {
                //writer = new StreamWriter("trial.xml");
                reader = new StreamReader(filename);
            }
            catch (System.IO.IOException e)
            {
                Console.WriteLine(e.StackTrace);
            }
            tmp = (Conf)xmlSerializer.Deserialize(reader);
            if (tmp == null || 
                tmp.database == null || 
                tmp.sites == null ||
                tmp.database.Tables ==null 
                )
            {
                return null;
            }
            foreach (Table t in tmp.database.Tables)
            {
                if(t.Columns == null)
                {
                    return null;
                }
                foreach(Column c in t.Columns)
                {
                    c.HasTableName = true;
                    c.IsAllColumn = false;
                    c.TableName = t.Name;
                }
            }
            return tmp;
        }

        public static bool SerializeConf(Conf conf, string filename)
        {
            System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Conf));
            
            TextWriter writer = null;
            try
            {
                writer = new StreamWriter(filename);
            }
            catch (System.IO.IOException e)
            {
                Console.WriteLine(e.StackTrace);
                return false;
            }
            xmlSerializer.Serialize(writer, conf);
            
            writer.Close();
            return true;
        }

        public static void SerializeTest()
        {
            Conf conf = new Conf();
            //Conf tmp = new Conf();
            conf.Sites = new List<Site>();
            conf.Database = new Database();
            conf.Database.Name = "ddb";
            Site site;
            for (int i = 1; i < 5; ++i)
            {
                site = new Site();
                site.Id = i;
                site.SiteName = "site" + i;
                site.Ip = "127.0.0.1";
                site.Port = 9000 + i;
                conf.Sites.Add(site);
            }


            conf.Database.Tables = new List<Table>();

            createPublisher(ref conf);
            createCustomer(ref conf);
            createBook(ref conf);
            createOrder(ref conf);
            
            Debug.Assert(SerializeConf(conf, "trial.xml"));      
            
        }
        public static void DeserializeTest()
         {
            
            Debug.Assert(DeSerializeConf("trial.xml")!=null);
            
        }
   
        private static void createPublisher(ref Conf conf)
        {
             //publisher
            Table table = new Table();
            conf.Database.Tables.Add(table);
            table.Name = "publisher";

            table.Columns = new List<Column>();
            
            Column col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "id";
            col.Length = 10;
            table.Columns.Add(col);
            table.PrimaryKey = col;
            
            col = new Column();
            col.DataType = DataType.VCAHR;
            col.ColumnName = "name";
            col.Length = 100;
            table.Columns.Add(col);

            col = new Column();
            col.DataType = DataType.VCAHR;
            col.ColumnName = "nation";
            col.Length = 3;
            table.Columns.Add(col);
            

            table.Fragments = new List<Fragment>();
            int rowsizes =113 ;
            int[] rowCounts = { 1994, 2005, 532,469 };

            ConditionType[] publisherTypes = { ConditionType.LT, ConditionType.LT, ConditionType.GE, ConditionType.GE };
            string[] publisherStrVal = { "PRC", "USA","PRC","USA" };
            for (int i = 0; i < 4; ++i)
            {
                HFragment f = new HFragment();
                f.Sites = new List<Site>();
                f.Sites.Add(conf.Sites.ElementAt(i));
                f.Id = i;
                table.Fragments.Add(f);
                f.TableName = table.Name;

                f.Cond = new Condition();
                f.Cond.Children = new List<Condition>();
                f.Cond.Type = ConditionType.AND;

                Condition cond = new Condition();
                cond.Children = new List<Condition>();
                cond.Type = publisherTypes[i];
                ColumnVal cval = new ColumnVal();
                cval.Type = ConditionType.COLUMN;
                cval.ColumnRef = table.Columns.First();
                IntVal ival = new IntVal();
                ival.Type = ConditionType.INTVAL;
                ival.Val = 104000;
                cond.Children.Add(cval);
                cond.Children.Add(ival);
                f.Cond.Children.Add(cond);

                cond = new Condition();
                cond.Children = new List<Condition>();
                cond.Type = ConditionType.EQ;
                cval = new ColumnVal();
                cval.Type = ConditionType.COLUMN;
                cval.ColumnRef = table.Columns.ElementAt(2);
                StrVal sval = new StrVal();
                sval.Type = ConditionType.STRVAL;
                sval.Val = publisherStrVal[i];
                cond.Children.Add(sval);
                cond.Children.Add(cval);
                f.Cond.Children.Add(cond);
            
            }
        
        
        }

        private static void createCustomer(ref Conf conf)
        {
            Table table = new Table();
            conf.Database.Tables.Add(table);
            table.Name = "customer";

            table.Columns = new List<Column>();

            Column col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "id";
            col.Length = 10;
            table.Columns.Add(col);
            table.PrimaryKey = col;

            col = new Column();
            col.DataType = DataType.VCAHR;
            col.ColumnName = "name";
            col.Length = 25;
            table.Columns.Add(col);

            col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "rank";
            col.Length = 10;
            table.Columns.Add(col);
            

            table.Fragments = new List<Fragment>();
            int[] rowsizes = { 35, 20 };
            int rowCounts = 15000;

            for (int i = 0; i < 2; ++i)
            {
                VFragment f = new VFragment();
                f.Sites = new List<Site>();
                f.Sites.Add(conf.Sites.ElementAt(i));
                f.Id = i;
                f.TableName = table.Name;
                f.RowCount = rowCounts;
                f.RowSize = rowsizes[i];
                table.Fragments.Add(f);

                f.ColumnRefs = new List<Column>();
                f.ColumnRefs.Add(table.Columns.First());
                f.ColumnRefs.Add(table.Columns.ElementAt(i+1));
                f.JoinColumn = table.Columns.First();
            }
        
        }

        private static void createBook(ref Conf conf)
        {
            Table table = new Table();
            conf.Database.Tables.Add(table);
            table.Name = "book";

            table.Columns = new List<Column>();

            Column col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "id";
            col.Length = 10;
            table.Columns.Add(col);
            table.PrimaryKey = col;

            col = new Column();
            col.DataType = DataType.VCAHR;
            col.ColumnName = "title";
            col.Length = 100;
            table.Columns.Add(col);

            col = new Column();
            col.DataType = DataType.VCAHR;
            col.ColumnName = "authors";
            col.Length = 25;
            table.Columns.Add(col);

            col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "publisher_id";
            col.Length = 10;
            table.Columns.Add(col);
            

            col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "copies";
            col.Length = 10;
            table.Columns.Add(col);
            

            table.Fragments = new List<Fragment>();

            ConditionType[] bookTypes = { ConditionType.LT, ConditionType.GE };
            int[] bookIntVal = { 205000, 210000 };
            int[] rowCounts={4999,5000,40001,40001};
            int rowsize = 330;
            for (int i = 0; i < 3; ++i)
            {
                HFragment f = new HFragment();
                f.RowCount = rowCounts[i];
                f.RowSize = rowsize;
                f.Sites = new List<Site>();
                f.Sites.Add(conf.Sites.ElementAt(i));
                f.Id = i;
                f.TableName = table.Name;
                if (i == 2)
                {
                    f.Sites.Add(conf.Sites.ElementAt(3));
                }
                table.Fragments.Add(f);
                if (i == 1)
                {
                    f.Cond = new Condition();
                    f.Cond.Children = new List<Condition>();
                    f.Cond.Type = ConditionType.AND;

                    Condition cond = new Condition();
                    cond.Children = new List<Condition>();
                    cond.Type = bookTypes[1];
                    ColumnVal cval = new ColumnVal();
                    cval.Type = ConditionType.COLUMN;
                    cval.ColumnRef = table.Columns.First();
                    IntVal ival = new IntVal();
                    ival.Type = ConditionType.INTVAL;
                    ival.Val = bookIntVal[0];
                    cond.Children.Add(cval);
                    cond.Children.Add(ival);
                    f.Cond.Children.Add(cond);

                    cond = new Condition();
                    cond.Children = new List<Condition>();
                    cond.Type = bookTypes[0];
                    cval = new ColumnVal();
                    cval.Type = ConditionType.COLUMN;
                    cval.ColumnRef = table.Columns.First();
                    ival = new IntVal();
                    ival.Type = ConditionType.INTVAL;
                    ival.Val = bookIntVal[1];
                    cond.Children.Add(cval);
                    cond.Children.Add(ival);
                    f.Cond.Children.Add(cond);
                }
                else {
                    f.Cond = new Condition();
                    f.Cond.Children = new List<Condition>();
                    //f.Cond.Type = ConditionType.AND;

                    Condition cond = f.Cond;
                    cond.Children = new List<Condition>();
                    cond.Type = bookTypes[i/2];
                    ColumnVal cval = new ColumnVal();
                    cval.Type = ConditionType.COLUMN;
                    cval.ColumnRef = table.Columns.First();
                    IntVal ival = new IntVal();
                    ival.Type = ConditionType.INTVAL;
                    ival.Val = bookIntVal[i/2];
                    cond.Children.Add(cval);
                    cond.Children.Add(ival);
                    //f.Cond.Children.Add(cond);
                
                
                }
            }
        }

        private static void createOrder(ref Conf conf)
        {
            Table table = new Table();
            conf.Database.Tables.Add(table);
            table.Name = "orders";

            table.Columns = new List<Column>();

            Column col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "customer_id";
            col.Length = 10;
            table.Columns.Add(col);
            table.PrimaryKey = col;

            col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "book_id";
            col.Length = 10;
            table.Columns.Add(col);
       

            col = new Column();
            col.DataType = DataType.INT;
            col.ColumnName = "quantity";
            col.Length = 10;
            table.Columns.Add(col);
           

            table.Fragments = new List<Fragment>();


            ConditionType[] orderTypes = { ConditionType.LT, ConditionType.LT, ConditionType.GE, ConditionType.GE,
                                         ConditionType.LT, ConditionType.GE, ConditionType.LT,  ConditionType.GE,
                                         };
            int[] rowCounts = { 14018, 32785, 16155, 37042 };
            int rowsize = 30;
            for (int i = 0; i < 4; ++i)
            {
                HFragment f = new HFragment();
                f.RowCount = rowCounts[i];
                f.RowSize = rowsize;
                f.Sites = new List<Site>();
                f.Sites.Add(conf.Sites.ElementAt(i));
                f.Id = i;
                f.TableName = table.Name;
                table.Fragments.Add(f);

                f.Cond = new Condition();
                f.Cond.Children = new List<Condition>();
                f.Cond.Type = ConditionType.AND;

                Condition cond = new Condition();
                cond.Children = new List<Condition>();
                cond.Type = orderTypes[i];
                ColumnVal cval = new ColumnVal();
                cval.Type = ConditionType.COLUMN;
                cval.ColumnRef = table.Columns.First();
                IntVal ival = new IntVal();
                ival.Type = ConditionType.INTVAL;
                ival.Val = 307000;
                cond.Children.Add(cval);
                cond.Children.Add(ival);
                f.Cond.Children.Add(cond);

                cond = new Condition();
                cond.Children = new List<Condition>();
                cond.Type = orderTypes[i+4];
                cval = new ColumnVal();
                cval.Type = ConditionType.COLUMN;
                cval.ColumnRef = table.Columns.ElementAt(1);
                ival = new IntVal();
                ival.Type = ConditionType.INTVAL;
                ival.Val = 215000;
                cond.Children.Add(cval);
                cond.Children.Add(ival);
                f.Cond.Children.Add(cond);

            }
        
        }

    }
    
}
